package com.gpslw.mvc;

import org.apache.commons.lang3.reflect.MethodUtils;

import javax.validation.Constraint;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import javax.validation.Payload;
import java.lang.annotation.*;
import java.lang.reflect.InvocationTargetException;

@Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER, ElementType.TYPE_USE})
@Retention(RetentionPolicy.RUNTIME)
@Repeatable(EnumValid.List.class)
@Documented
@Constraint(
        validatedBy = {EnumValid.EnumValidator.class}
)
public @interface EnumValid {


    String message() default "{com.gpslw.mvc.EnumValid.message}";

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};

    @Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER, ElementType.TYPE_USE})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface List {
        EnumValid[] value();
    }

    Class<? extends Enum<?>> enumType();

    String verifyMethod() default "isValid";

    boolean necessity() default false;

    public static class EnumValidator implements ConstraintValidator<EnumValid,Object> {

        private String verifyMethod;

        private Class enumClass;

        private boolean necessity;


        @Override
        public void initialize(EnumValid constraintAnnotation) {

            this.verifyMethod = constraintAnnotation.verifyMethod();

            this.enumClass = constraintAnnotation.enumType();

            this.necessity = constraintAnnotation.necessity();

        }

        @Override
        public boolean isValid(Object value, ConstraintValidatorContext constraintValidatorContext) {
            if (value == null){
                return !this.necessity;
            }
            try {
                return (boolean) MethodUtils.invokeStaticMethod(enumClass, verifyMethod, value);
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
            return false;
        }
    }
}
